package com.project.srtp.secure.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.srtp.secure.dao.entity.PreKeyDO;
import com.project.srtp.secure.dao.mapper.PreKeyMapper;
import com.project.srtp.secure.dto.req.PreKeyReqDTO;
import com.project.srtp.secure.dto.resp.HasPreKeyRespDTO;
import com.project.srtp.secure.service.PreKeyService;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author 曹行阳
 * @version 0.1
 * @date 2025/6/16 12:31
 */
@Service
public class PreKeyServiceImpl extends ServiceImpl<PreKeyMapper, PreKeyDO> implements PreKeyService {
    @Override
    @Transactional
    public void storePreKeys(List<PreKeyReqDTO> preKeys, String userId) {
        if (preKeys == null || preKeys.isEmpty()) {
            return;
        }

        for (PreKeyReqDTO req : preKeys) {
            PreKeyDO doObj = PreKeyDO.builder()
                    .userId(userId)
                    .keyId(req.getId())
                    .publicKey(req.getPublicKey())
                    .cipher(req.getCipher())
                    .salt(req.getSalt())
                    .used(Boolean.FALSE)
                    .build();

            try {
                int updated = baseMapper.update(
                        doObj,
                        new UpdateWrapper<PreKeyDO>()
                                .eq("user_id", userId)
                                .eq("key_id", req.getId())
                );

                if (updated == 0) {
                    baseMapper.insert(doObj);
                }
            } catch (DuplicateKeyException e) {
                log.error("PreKey already exists");
            }
        }
    }

    @Override
    public List<PreKeyDO> selectPreKeysByUserId(String userId) {
        LambdaQueryWrapper<PreKeyDO> queryWrapper = Wrappers.lambdaQuery(PreKeyDO.class)
                .eq(PreKeyDO::getUserId, userId)
                .eq(PreKeyDO::getUsed, Boolean.FALSE)
                .orderByAsc(PreKeyDO::getKeyId)
                .last("LIMIT 10");
        try {
            List<PreKeyDO> preKeys = baseMapper.selectList(queryWrapper);
            if (preKeys == null || preKeys.isEmpty()) {
                log.error("未找到用户预共享密钥");
                return List.of();
            }
            return preKeys;
        } catch (Exception e) {
            log.error("用户不存在");
        }
        return List.of();
    }

    @Override
    public PreKeyDO selectPreKeyByUserId(String userId) {
        LambdaQueryWrapper<PreKeyDO> queryWrapper = Wrappers.lambdaQuery(PreKeyDO.class)
                .eq(PreKeyDO::getUserId, userId)
                .eq(PreKeyDO::getUsed, Boolean.FALSE)
                .orderByAsc(PreKeyDO::getKeyId)
                .last("LIMIT 1");
        try {
            PreKeyDO preKeyDO = baseMapper.selectOne(queryWrapper);

            if (preKeyDO == null) {
                log.error("未找到用户预共享密钥");
                return null;
            }
            return preKeyDO;
        } catch (Exception e) {
            log.error("用户不存在");
        }
        return null;
    }

    @Override
    @Transactional
    public void deletePreKey(PreKeyDO preKey) {
        baseMapper.deleteById(preKey.getId());
    }

    @Override
    @Transactional
    public void setPreKeyUser(PreKeyDO preKey) {
        UpdateWrapper<PreKeyDO> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", preKey.getId()).set("used", true);
        baseMapper.update(null, wrapper);
    }

    @Override
    public HasPreKeyRespDTO hasPreKey(String userId) {
        LambdaQueryWrapper<PreKeyDO> queryWrapper = Wrappers.lambdaQuery(PreKeyDO.class)
                .eq(PreKeyDO::getUsed, Boolean.FALSE)
                .eq(PreKeyDO::getUserId, userId)
                .orderByAsc(PreKeyDO::getKeyId);
        LambdaQueryWrapper<PreKeyDO> queryWrapperForMaxId = Wrappers.lambdaQuery(PreKeyDO.class)
                .eq(PreKeyDO::getUserId, userId)
                .orderByDesc(PreKeyDO::getKeyId)
                .last("LIMIT 1");
        try {
            List<PreKeyDO> preKeys = baseMapper.selectList(queryWrapper);
            PreKeyDO maxPreKeyDO = baseMapper.selectOne(queryWrapperForMaxId);

            boolean hasPreKey = preKeys != null && preKeys.size() >= 5;
            Integer maxPreKeyId = maxPreKeyDO.getKeyId();
            HasPreKeyRespDTO respDTO = new HasPreKeyRespDTO();
            respDTO.setHasPreKey(hasPreKey);
            respDTO.setMaxPreKeyId(maxPreKeyId);
            return respDTO;
        } catch (Exception e) {
            throw new RuntimeException("预密钥获取失败", e);
        }
    }
}
